x86, vt-d: Clean up utils code.
authorKeir Fraser <keir@xensource.com>
Thu, 8 Nov 2007 13:14:03 +0000 (13:14 +0000)
committerKeir Fraser <keir@xensource.com>
Thu, 8 Nov 2007 13:14:03 +0000 (13:14 +0000)
Signed-off-by: Weidong Han <weidong.han@intel.com>
xen/arch/x86/hvm/vmx/vtd/intel-iommu.c
xen/arch/x86/hvm/vmx/vtd/utils.c
xen/include/asm-x86/hvm/vmx/intel-iommu.h

index ae9a9f26dbbbb58998240e0360a345213b993237..0598a3bafc5f478cf1a1e571fc967b0f8cc2c6c3 100644 (file)
@@ -115,18 +115,6 @@ static int device_context_mapped(struct iommu *iommu, u8 bus, u8 devfn)
     return ret;
 }
 
-/* page table handling */
-#define LEVEL_STRIDE        (9)
-#define LEVEL_MASK        ((1 << LEVEL_STRIDE) - 1)
-#define agaw_to_level(val) ((val) + 2)
-#define agaw_to_width(val) (30 + val * LEVEL_STRIDE)
-#define width_to_agaw(w)  ((w - 30)/LEVEL_STRIDE)
-#define level_to_offset_bits(l) (12 + (l - 1) * LEVEL_STRIDE)
-#define address_level_offset(addr, level) \
-    ((addr >> level_to_offset_bits(level)) & LEVEL_MASK)
-#define level_mask(l) (((u64)(-1)) << level_to_offset_bits(l))
-#define level_size(l) (1 << level_to_offset_bits(l))
-#define align_to_level(addr, l) ((addr + level_size(l) - 1) & level_mask(l))
 static struct page_info *addr_to_dma_page(struct domain *domain, u64 addr)
 {
     struct hvm_iommu *hd = domain_hvm_iommu(domain);
index 1ef25d4e989c5aa7cbd0ecfd10a2705428bdca42..b15af311c7d785bb3d59bd71dd224632f993a9fc 100644 (file)
@@ -32,8 +32,9 @@
 
 #include <xen/mm.h>
 #include <xen/xmalloc.h>
+#include <xen/inttypes.h>
 
-#define VTDPREFIX "[VT-D]" 
+#define VTDPREFIX "[VT-D]"
 #define INTEL   0x8086
 #define SEABURG 0x4000
 #define C_STEP  2
@@ -93,181 +94,57 @@ void disable_pmr(struct iommu *iommu)
             "Disabled protected memory registers\n");
 }
 
-#if defined(__x86_64__)
+
 void print_iommu_regs(struct acpi_drhd_unit *drhd)
 {
     struct iommu *iommu = drhd->iommu;
-    printk("---- print_iommu_regs ----\n"); 
+
+    printk("---- print_iommu_regs ----\n");
     printk("print_iommu_regs: drhd->address = %lx\n", drhd->address);
     printk("print_iommu_regs: DMAR_VER_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_VER_REG));
-    printk("print_iommu_regs: DMAR_CAP_REG = %lx\n",
-                   dmar_readq(iommu->reg,DMAR_CAP_REG));
-    printk("print_iommu_regs: n_fault_reg = %lx\n",
-                   cap_num_fault_regs(dmar_readq(iommu->reg, DMAR_CAP_REG)));
-    printk("print_iommu_regs: fault_recording_offset_l = %lx\n",
-                   cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)));
-    printk("print_iommu_regs: fault_recording_offset_h = %lx\n",
-                   cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8);
-    printk("print_iommu_regs: fault_recording_reg_l = %lx\n",
-        dmar_readq(iommu->reg, cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG))));
-    printk("print_iommu_regs: fault_recording_reg_h = %lx\n",
-        dmar_readq(iommu->reg, cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8));
-    printk("print_iommu_regs: DMAR_ECAP_REG = %lx\n",
-                   dmar_readq(iommu->reg,DMAR_ECAP_REG));
+           dmar_readl(iommu->reg,DMAR_VER_REG));
+    printk("print_iommu_regs: DMAR_CAP_REG = %"PRIx64"\n",
+           dmar_readq(iommu->reg,DMAR_CAP_REG));
+    printk("print_iommu_regs: n_fault_reg = %"PRIx64"\n",
+           cap_num_fault_regs(dmar_readq(iommu->reg, DMAR_CAP_REG)));
+    printk("print_iommu_regs: fault_recording_offset_l = %"PRIx64"\n",
+           cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)));
+    printk("print_iommu_regs: fault_recording_offset_h = %"PRIx64"\n",
+           cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8);
+    printk("print_iommu_regs: fault_recording_reg_l = %"PRIx64"\n",
+           dmar_readq(iommu->reg,
+               cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG))));
+    printk("print_iommu_regs: fault_recording_reg_h = %"PRIx64"\n",
+           dmar_readq(iommu->reg,
+               cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8));
+    printk("print_iommu_regs: DMAR_ECAP_REG = %"PRIx64"\n",
+           dmar_readq(iommu->reg,DMAR_ECAP_REG));
     printk("print_iommu_regs: DMAR_GCMD_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_GCMD_REG));
+           dmar_readl(iommu->reg,DMAR_GCMD_REG));
     printk("print_iommu_regs: DMAR_GSTS_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_GSTS_REG));
-    printk("print_iommu_regs: DMAR_RTADDR_REG = %lx\n",
-                   dmar_readq(iommu->reg,DMAR_RTADDR_REG));
-    printk("print_iommu_regs: DMAR_CCMD_REG = %lx\n",
-                   dmar_readq(iommu->reg,DMAR_CCMD_REG));
+           dmar_readl(iommu->reg,DMAR_GSTS_REG));
+    printk("print_iommu_regs: DMAR_RTADDR_REG = %"PRIx64"\n",
+           dmar_readq(iommu->reg,DMAR_RTADDR_REG));
+    printk("print_iommu_regs: DMAR_CCMD_REG = %"PRIx64"\n",
+           dmar_readq(iommu->reg,DMAR_CCMD_REG));
     printk("print_iommu_regs: DMAR_FSTS_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FSTS_REG));
+           dmar_readl(iommu->reg,DMAR_FSTS_REG));
     printk("print_iommu_regs: DMAR_FECTL_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FECTL_REG));
+           dmar_readl(iommu->reg,DMAR_FECTL_REG));
     printk("print_iommu_regs: DMAR_FEDATA_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FEDATA_REG));
+           dmar_readl(iommu->reg,DMAR_FEDATA_REG));
     printk("print_iommu_regs: DMAR_FEADDR_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FEADDR_REG));
+           dmar_readl(iommu->reg,DMAR_FEADDR_REG));
     printk("print_iommu_regs: DMAR_FEUADDR_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FEUADDR_REG));
+           dmar_readl(iommu->reg,DMAR_FEUADDR_REG));
 }
 
-void print_vtd_entries(struct domain *d, int bus, int devfn,
-                       unsigned long gmfn)
+u32 get_level_index(unsigned long gmfn, int level)
 {
-    struct hvm_iommu *hd = domain_hvm_iommu(d);
-    struct acpi_drhd_unit *drhd;
-    struct iommu *iommu;
-    struct context_entry *ctxt_entry;
-    struct root_entry *root_entry;
-    u64 *l3, *l2, *l1;
-    u32 l3_index, l2_index, l1_index;
-    u32 i = 0;
-
-    printk("print_vtd_entries: domain_id = %x bdf = %x:%x:%x devfn = %x, gmfn = %lx\n", d->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), devfn, gmfn);
-
-    for_each_drhd_unit(drhd) {
-        printk("---- print_vtd_entries %d ----\n", i++);
-
-        if (hd->pgd == NULL) {
-            printk("    hg->pgd == NULL\n");
-            return;
-        }
-
-        iommu = drhd->iommu;
-        root_entry = iommu->root_entry;
-        printk("    hd->pgd = %p virt_to_maddr(hd->pgd) = %lx\n",
-               hd->pgd, virt_to_maddr(hd->pgd));
-
-        printk("    root_entry = %p\n", root_entry);
-        if (root_entry == NULL) {
-            printk("    root_entry == NULL\n");
-            return;
-        }
-
-        printk("    root_entry[%x] = %lx\n", bus, root_entry[bus].val);
-        printk("    maddr_to_virt(root_entry[%x]) = %p\n",
-            bus, maddr_to_virt(root_entry[bus].val));
-
-        if (root_entry[bus].val == 0) {
-            printk("    root_entry[%x].lo == 0\n", bus);
-            return;
-        }
-        ctxt_entry = maddr_to_virt((root_entry[bus].val >> PAGE_SHIFT) << PAGE_SHIFT);
-        if (ctxt_entry == NULL) {
-            printk("    ctxt_entry == NULL\n");
-            return;
-        }
-
-        if (ctxt_entry[devfn].lo == 0) {
-            printk("    ctxt_entry[%x].lo == 0\n", devfn);
-            return;
-        }
-
-        printk("    context = %p\n", ctxt_entry);
-        printk("    context[%x] = %lx %lx\n",
-               devfn, ctxt_entry[devfn].hi, ctxt_entry[devfn].lo);
-        printk("    maddr_to_virt(context[%x].lo) = %p\n",
-               devfn, maddr_to_virt(ctxt_entry[devfn].lo));
-        printk("    context[%x] = %lx\n", devfn, ctxt_entry[devfn].lo); 
-
-        l3 = maddr_to_virt(ctxt_entry[devfn].lo);
-        l3 = (u64*)(((u64) l3 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
-        printk("    l3 = %p\n", l3); 
-        if (l3 == NULL) return;
-
-        l3_index = (gmfn >> 9 >> 9) & 0x1ff;
-        printk("    l3_index = %x\n", l3_index);
-        printk("    l3[%x] = %lx\n", l3_index, l3[l3_index]);
-
-        l2 = maddr_to_virt(l3[l3_index]);
-        l2 = (u64*)(((u64) l2 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
-        printk("    l2 = %p\n", l2); 
-        if (l2 == NULL) return;
+    while ( --level )
+        gmfn = gmfn >> LEVEL_STRIDE;
 
-        l2_index = (gmfn >> 9) & 0x1ff;
-        printk("    gmfn = %lx\n", gmfn);
-        printk("    gmfn >> 9= %lx\n", gmfn >> 9);
-        printk("    l2_index = %x\n", l2_index);
-        printk("    l2[%x] = %lx\n", l2_index, l2[l2_index]);
-
-        l1 = maddr_to_virt(l2[l2_index]);
-        l1 = (u64*)(((u64) l1 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
-        if (l1 == NULL) return;
-        l1_index = gmfn & 0x1ff;
-        printk("    l1 = %p\n", l1); 
-        printk("    l1_index = %x\n", l1_index);
-        printk("    l1[%x] = %lx\n", l1_index, l1[l1_index]); 
-    }
-}
-
-#else    // !m64
-
-void print_iommu_regs(struct acpi_drhd_unit *drhd)
-{
-    struct iommu *iommu = drhd->iommu;
-    printk("---- print_iommu_regs ----\n"); 
-    printk("print_iommu_regs: drhd->address = %lx\n", drhd->address);
-    printk("print_iommu_regs: DMAR_VER_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_VER_REG));
-    printk("print_iommu_regs: DMAR_CAP_REG = %llx\n",
-                   dmar_readq(iommu->reg,DMAR_CAP_REG));
-    printk("print_iommu_regs: n_fault_reg = %llx\n",
-                   cap_num_fault_regs(dmar_readq(iommu->reg, DMAR_CAP_REG)));
-    printk("print_iommu_regs: fault_recording_offset_l = %llx\n",
-                   cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)));
-    printk("print_iommu_regs: fault_recording_offset_h = %llx\n",
-                   cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8);
-    printk("print_iommu_regs: fault_recording_reg_l = %llx\n",
-        dmar_readq(iommu->reg, cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG))));
-    printk("print_iommu_regs: fault_recording_reg_h = %llx\n",
-        dmar_readq(iommu->reg, cap_fault_reg_offset(dmar_readq(iommu->reg, DMAR_CAP_REG)) + 8));
-    printk("print_iommu_regs: DMAR_ECAP_REG = %llx\n",
-                   dmar_readq(iommu->reg,DMAR_ECAP_REG));
-    printk("print_iommu_regs: DMAR_GCMD_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_GCMD_REG));
-    printk("print_iommu_regs: DMAR_GSTS_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_GSTS_REG));
-    printk("print_iommu_regs: DMAR_RTADDR_REG = %llx\n",
-                   dmar_readq(iommu->reg,DMAR_RTADDR_REG));
-    printk("print_iommu_regs: DMAR_CCMD_REG = %llx\n",
-                   dmar_readq(iommu->reg,DMAR_CCMD_REG));
-    printk("print_iommu_regs: DMAR_FSTS_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FSTS_REG));
-    printk("print_iommu_regs: DMAR_FECTL_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FECTL_REG));
-    printk("print_iommu_regs: DMAR_FEDATA_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FEDATA_REG));
-    printk("print_iommu_regs: DMAR_FEADDR_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FEADDR_REG));
-    printk("print_iommu_regs: DMAR_FEUADDR_REG = %x\n",
-                   dmar_readl(iommu->reg,DMAR_FEUADDR_REG));
+    return gmfn & LEVEL_MASK;
 }
 
 void print_vtd_entries(struct domain *d, int bus, int devfn,
@@ -278,85 +155,120 @@ void print_vtd_entries(struct domain *d, int bus, int devfn,
     struct iommu *iommu;
     struct context_entry *ctxt_entry;
     struct root_entry *root_entry;
-    u64 *l3, *l2, *l1;
-    u32 l3_index, l2_index, l1_index;
+    u64 *l4 = NULL, *l3, *l2, *l1;
+    u32 l4_index = 0, l3_index, l2_index, l1_index;
     u32 i = 0;
+    int level = agaw_to_level(hd->agaw);
 
-    printk("print_vtd_entries: domain_id = %x bdf = %x:%x:%x devfn = %x, gmfn = %lx\n", d->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), devfn, gmfn);
+    printk("print_vtd_entries: domain_id = %x bdf = %x:%x:%x gmfn = %lx\n",
+           d->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn);
 
-    for_each_drhd_unit(drhd) {
-        printk("---- print_vtd_entries %d ----\n", i++);
+    if ( hd->pgd == NULL )
+    {
+        printk("    hg->pgd == NULL\n");
+        return;
+    }
+    printk("    d->pgd = %p virt_to_maddr(hd->pgd) = %lx\n",
+           hd->pgd, virt_to_maddr(hd->pgd));
 
-        if (hd->pgd == NULL) {
-            printk("    hg->pgd == NULL\n");
-            return;
-        }
+    for_each_drhd_unit ( drhd )
+    {
+        printk("---- print_vtd_entries %d ----\n", i++);
 
         iommu = drhd->iommu;
         root_entry = iommu->root_entry;
-        printk("    d->pgd = %p virt_to_maddr(hd->pgd) = %lx\n",
-               hd->pgd, virt_to_maddr(hd->pgd));
-
         printk("    root_entry = %p\n", root_entry);
-        if (root_entry == NULL) {
+        if ( root_entry == NULL )
+        {
             printk("    root_entry == NULL\n");
-            return;
+            continue;
         }
 
-        printk("    root_entry[%x] = %llx\n", bus, root_entry[bus].val);
+        printk("    root_entry[%x] = %"PRIx64"\n", bus, root_entry[bus].val);
         printk("    maddr_to_virt(root_entry[%x]) = %p\n",
-            bus, maddr_to_virt(root_entry[bus].val));
+               bus, maddr_to_virt(root_entry[bus].val));
 
-        if (root_entry[bus].val == 0) {
+        if ( root_entry[bus].val == 0 )
+        {
             printk("    root_entry[%x].lo == 0\n", bus);
-            return;
+            continue;
         }
-        ctxt_entry = maddr_to_virt((root_entry[bus].val >> PAGE_SHIFT) << PAGE_SHIFT);
-        if (ctxt_entry == NULL) {
+
+        ctxt_entry =
+            maddr_to_virt((root_entry[bus].val >> PAGE_SHIFT) << PAGE_SHIFT);
+        if ( ctxt_entry == NULL )
+        {
             printk("    ctxt_entry == NULL\n");
-            return;
+            continue;
         }
 
-        if (ctxt_entry[devfn].lo == 0) {
+        if ( ctxt_entry[devfn].lo == 0 )
+        {
             printk("    ctxt_entry[%x].lo == 0\n", devfn);
-            return;
+            continue;
         }
 
         printk("    context = %p\n", ctxt_entry);
-        printk("    context[%x] = %llx %llx\n",
+        printk("    context[%x] = %"PRIx64" %"PRIx64"\n",
                devfn, ctxt_entry[devfn].hi, ctxt_entry[devfn].lo);
         printk("    maddr_to_virt(context[%x].lo) = %p\n",
                devfn, maddr_to_virt(ctxt_entry[devfn].lo));
-        printk("    context[%x] = %llx\n", devfn, ctxt_entry[devfn].lo); 
+        printk("    context[%x] = %"PRIx64"\n", devfn, ctxt_entry[devfn].lo);
+
+        switch ( level )
+        {
+        case VTD_PAGE_TABLE_LEVEL_3:
+            l3 = maddr_to_virt(ctxt_entry[devfn].lo);
+            l3 = (u64*)(((unsigned long)l3 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
+            printk("    l3 = %p\n", l3);
+            if ( l3 == NULL )
+                continue;
+            l3_index = get_level_index(gmfn, 3);
+            printk("    l3_index = %x\n", l3_index);
+            printk("    l3[%x] = %"PRIx64"\n", l3_index, l3[l3_index]);
 
-        l3 = maddr_to_virt(ctxt_entry[devfn].lo);
-        l3 = (u64*)(((u32) l3 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
-        printk("    l3 = %p\n", l3); 
-        if (l3 == NULL) return;
+            break;
+        case VTD_PAGE_TABLE_LEVEL_4:
+            l4 = maddr_to_virt(ctxt_entry[devfn].lo);
+            l4 = (u64*)(((unsigned long)l4 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
+            printk("    l4 = %p\n", l4);
+            if ( l4 == NULL )
+                continue;
+            l4_index = get_level_index(gmfn, 4);
+            printk("    l4_index = %x\n", l4_index);
+            printk("    l4[%x] = %"PRIx64"\n", l4_index, l4[l4_index]);
+
+            l3 = maddr_to_virt(l4[l4_index]);
+            l3 = (u64*)(((unsigned long)l3 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
+            printk("    l3 = %p\n", l3);
+            if ( l3 == NULL )
+                continue;
+            l3_index = get_level_index(gmfn, 3);
+            printk("    l3_index = %x\n", l3_index);
+            printk("    l3[%x] = %"PRIx64"\n", l3_index, l3[l3_index]);
 
-        l3_index = (gmfn >> 9 >> 9) & 0x1ff;
-        printk("    l3_index = %x\n", l3_index);
-        printk("    l3[%x] = %llx\n", l3_index, l3[l3_index]);
+            break;
+        default:
+            printk("Unsupported VTD page table level (%d)!\n", level);
+            continue;
+        }
 
         l2 = maddr_to_virt(l3[l3_index]);
-        l2 = (u64*)(((u32) l2 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
-        printk("    l2 = %p\n", l2); 
-        if (l2 == NULL) return;
-
-        l2_index = (gmfn >> 9) & 0x1ff;
-        printk("    gmfn = %lx\n", gmfn);
-        printk("    gmfn >> 9= %lx\n", gmfn >> 9);
+        l2 = (u64*)(((unsigned long)l2 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
+        printk("    l2 = %p\n", l2);
+        if ( l2 == NULL )
+            continue;
+        l2_index = get_level_index(gmfn, 2);
         printk("    l2_index = %x\n", l2_index);
-        printk("    l2[%x] = %llx\n", l2_index, l2[l2_index]);
+        printk("    l2[%x] = %"PRIx64"\n", l2_index, l2[l2_index]);
 
         l1 = maddr_to_virt(l2[l2_index]);
-        l1 = (u64*)(((u32) l1 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
-        if (l1 == NULL) return;
-        l1_index = gmfn & 0x1ff;
-        printk("    l1 = %p\n", l1); 
+        l1 = (u64*)(((unsigned long)l1 >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
+        printk("    l1 = %p\n", l1);
+        if ( l1 == NULL )
+            continue;
+        l1_index = get_level_index(gmfn, 1);
         printk("    l1_index = %x\n", l1_index);
-        printk("    l1[%x] = %llx\n", l1_index, l1[l1_index]); 
-    }
+        printk("    l1[%x] = %"PRIx64"\n", l1_index, l1[l1_index]);
+   }
 }
-#endif    // !m64
index b4c7d410bf4d984ab3fa499d67a74eec80f2ce46..c97cc3a5e63886765e54181062df6f3a99c3ca76 100644 (file)
@@ -230,6 +230,19 @@ struct context_entry {
     do {(c).hi &= 0xff; (c).hi |= ((val + 1) & ((1 << 16) - 1)) << 8;} while(0)
 #define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while(0)
 
+/* page table handling */
+#define LEVEL_STRIDE       (9)
+#define LEVEL_MASK         ((1 << LEVEL_STRIDE) - 1)
+#define agaw_to_level(val) ((val) + 2)
+#define agaw_to_width(val) (30 + val * LEVEL_STRIDE)
+#define width_to_agaw(w)   ((w - 30)/LEVEL_STRIDE)
+#define level_to_offset_bits(l) (12 + (l - 1) * LEVEL_STRIDE)
+#define address_level_offset(addr, level) \
+            ((addr >> level_to_offset_bits(level)) & LEVEL_MASK)
+#define level_mask(l) (((u64)(-1)) << level_to_offset_bits(l))
+#define level_size(l) (1 << level_to_offset_bits(l))
+#define align_to_level(addr, l) ((addr + level_size(l) - 1) & level_mask(l))
+
 /*
  * 0: readable
  * 1: writable